home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / EAGLE.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  25KB  |  803 lines

  1. /*
  2.  * Interface driver for the EAGLE board for KA9Q's TCP/IP on an IBM-PC ONLY!
  3.  *
  4.  *  Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
  5.  *  Permission for non-commercial use is hereby granted provided this notice
  6.  *  is retained.  For info call: (301) 997-3838.
  7.  *
  8.  *  10 Jan 88    ng6q    - Corrected IDLE comparison in doegstat.
  9.  *   6 Apr 88    ng6q    - Changed eg_raw to prevent calling egtxint with a
  10.  *              packet in sndbuf.  Initialized sndq and rcvq in
  11.  *              eg_attach.  Added carrier detect check before
  12.  *              slot time delay in egtxint.  Should make major
  13.  *              changes to egtxint to avoid delay loops while
  14.  *              masked for receive interrupts.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <dos.h>
  19. #include "global.h"
  20. #include "mbuf.h"
  21. #include "iface.h"
  22. #include "eagle.h"
  23. #include "8530.h"
  24. #include "ax25.h"
  25. #include "trace.h"
  26. #include "pc.h"
  27. #include <time.h>
  28.  
  29. static int eg_ctl __ARGS((struct iface *iface,int argc,char *argv[]));
  30. static int eg_raw __ARGS((struct iface *iface,struct mbuf *bp));
  31. static int eg_stop __ARGS((struct iface *iface));
  32. static void egchanparam __ARGS((struct egchan *hp));
  33. static void egexint __ARGS((struct egchan *hp));
  34. static void egrxint __ARGS((struct egchan *hp));
  35. static void egtxint __ARGS((struct egchan *hp));
  36. static void rts __ARGS((struct egchan *hp,int16 x));
  37. static void waitmsec __ARGS((int n));
  38.  
  39. static struct EGTAB Eagle[EGMAX];    /* Device table - one entry per card */
  40. static INTERRUPT (*eghandle[])() = {    /* handler interrupt vector table */
  41.     eg0vec,    
  42. };
  43. static struct egchan Egchan[2*EGMAX];    /* channel table - 2 entries per card */
  44. static int16 Egnbr;
  45.  
  46. /* Master interrupt handler.  One interrupt at a time is handled.
  47.  * here. Service routines are called from here.
  48.  */
  49. void
  50. egint(dev)
  51. int16 dev;
  52. {
  53.     register char st;
  54.     register int16 pcbase;
  55.     struct egchan *hp;
  56.  
  57.     Eagle[dev].ints++;
  58.     pcbase = Eagle[dev].addr;
  59.  
  60.     /* Read interrupt status register from channel A */
  61.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0) {
  62.         /* Use IFs to process ALL interrupts pending
  63.          * because we need to check all interrupt conditions
  64.          */
  65.         if (st & CHARxIP) {
  66.             /* Channel A Rcv Interrupt Pending */
  67.             hp = &Egchan[2 * dev];
  68.             egrxint(hp);
  69.         } else if (st & CHATxIP) {
  70.             /* Channel A Transmit Int Pending */
  71.             hp = &Egchan[2 * dev];
  72.             egtxint(hp);
  73.         } else if (st & CHAEXT) {
  74.             /* Channel A External Status Int */
  75.             hp = &Egchan[2 * dev];
  76.             egexint(hp);
  77.         } else if (st & CHBRxIP) {
  78.             /* Channel B Rcv Interrupt Pending */
  79.             hp = &Egchan[(2 * dev)+1];
  80.             egrxint(hp);
  81.         } else if (st & CHBTxIP) {
  82.             /* Channel B Transmit Int Pending */
  83.             hp = &Egchan[(2 * dev)+1];
  84.             egtxint(hp);
  85.         } else if (st & CHBEXT) {
  86.             /* Channel B External Status Int */
  87.             hp = &Egchan[(2 * dev)+1];
  88.             egexint(hp);
  89.         }
  90.         /* Reset highest interrupt under service */
  91.         write_scc(hp->base+CTL,R0,RES_H_IUS);
  92.     } /* End of while loop on int processing */
  93. }
  94.  
  95. /* Eagle SIO External/Status interrupts
  96.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  97.  * Receiver automatically goes to Hunt on an abort.
  98.  *
  99.  * If the Tx Underrun interrupt hits, change state and
  100.  * issue a reset command for it, and return.
  101.  */
  102. static void
  103. egexint(hp)
  104. register struct egchan *hp;
  105. {
  106.     char st, i_state;
  107.  
  108.     i_state = dirps();        /* disable interrupts */
  109.     hp->exints++;
  110.     st = read_scc(hp->base+CTL,R0);     /* Fetch status */
  111.  
  112.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  113.     if((hp->rstate==0) && (st & TxEOM)) {
  114.         /* if in UNDERRUN, go to FLAGOUT state
  115.          * see explanation under egtxint()
  116.          * CRC & FLAG now going out, so
  117.          * wait for Tx BUffer Empty int
  118.          */
  119.  
  120.         /* If we are not in underrun, this is an unexpected
  121.          * underrun.  EOM bit should be set, so the SCC will
  122.          * now send an abort
  123.          */
  124.  
  125.         if(hp->tstate == UNDERRUN)
  126.             hp->tstate = FLAGOUT;
  127.  
  128.         /* Tx Buff EMPTY interrupt occurs after CRC is sent */
  129.     }
  130.  
  131.     /* Receive Mode only
  132.      * This triggers when hunt mode is entered, & since an ABORT
  133.      * automatically enters hunt mode, we use that to clean up
  134.      * any waiting garbage
  135.      */
  136.     if((hp->rstate == ACTIVE) && (st & BRK_ABRT)) {
  137.         hp->rcp = hp->rcvbuf->data;
  138.         hp->rcvbuf->cnt = 0;          /* rewind on DCD transition */
  139.         hp->aborts++;              /* nbr aborts * 2 */
  140.     }
  141.  
  142.     /* reset external status latch */
  143.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  144.  
  145.     restore(i_state);
  146. }
  147.  
  148. /* EG receive interrupt handler. The first receive buffer is pre-allocated
  149.  * in the init routine.  Thereafter, it is filled here, queued out, and a
  150.  * new one acquired.  CRC, OVERRUN and TOOBIG errors merely 'rewind' the
  151.  * pointers and reuse the same buffer.
  152.  */
  153. static void
  154. egrxint(hp)
  155. register struct egchan *hp;
  156. {
  157.     register int16 base;
  158.     char rse, i_state;
  159.     struct mbuf *bp;
  160.     struct phdr *phdr;
  161.  
  162.     i_state = dirps();        /* disable interrupts */
  163.     hp->rxints++;
  164.     base = hp->base;
  165.  
  166.     if ((read_scc(base+CTL,R0)) & Rx_CH_AV) {
  167.         /* there is a char to be stored
  168.          * read special condition bits before reading the data char
  169.          */
  170.         rse = read_scc(hp->base+CTL,R1); /* get status byte from R1 */
  171.         if(rse & Rx_OVR) {
  172.             /* Rx overrun - toss buffer */
  173.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  174.             hp->rcvbuf->cnt = 0;
  175.             hp->rstate = RXERROR;    /* set error flag */
  176.             hp->rovers++;        /* count overruns */
  177.         } else if(hp->rcvbuf->cnt >= hp->bufsiz) {
  178.             /* Too large -- toss buffer */
  179.             hp->toobig++;
  180.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  181.             hp->rcvbuf->cnt = 0;
  182.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  183.         }
  184.         /* ok, we can store the received character now */
  185.         if(hp->rstate == ACTIVE) {        /* If no errors... */
  186.             *hp->rcp++ = inportb(base+DATA);    /* char to rcv buff */
  187.             hp->rcvbuf->cnt++;            /* bump count */
  188.         } else {
  189.             /* got to empty FIFO */
  190.             (void) inportb(base+DATA);
  191.             write_scc(hp->base+CTL,R0,ERR_RES);    /* reset err latch */
  192.             hp->rstate = ACTIVE;
  193.         }
  194.     }
  195.     /* char has been stored
  196.      * read special condition bits
  197.      */
  198.     rse = read_scc(hp->base+CTL,R1);     /* get status byte from R1 */
  199.  
  200.     /* The End of Frame bit is ALWAYS associated with a character,
  201.      * usually, it is the last CRC char.  Only when EOF is true can
  202.      * we look at the CRC byte to see if we have a valid frame
  203.      */
  204.     if(rse & END_FR) {
  205.         hp->rxframes++;
  206.         /* END OF FRAME -- Make sure Rx was active */
  207.         if(hp->rcvbuf->cnt > 0) {        /* any data to store */
  208.             /* looks like a frame was received
  209.              * now is the only time we can check for CRC error
  210.              */
  211.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) || (hp->rcvbuf->cnt < 10)) {
  212.                 /* error occurred; toss frame */
  213.                 if(rse & CRC_ERR)
  214.                     hp->crcerr++;    /* count CRC errs */
  215.                 if(hp->rstate == RXERROR)
  216.                     hp->rovers++;
  217.                 /* don't throw away buffer -
  218.                  * merely reset the pointers
  219.                  */
  220.                 hp->rcp = hp->rcvbuf->data;
  221.                 hp->rcvbuf->cnt = 0;
  222.             } else {
  223.                 /* Here we have a valid frame */
  224.                 hp->rcvbuf->cnt -= 2;           /* Toss 2 crc bytes */
  225.                 bp = alloc_mbuf(sizeof(struct phdr));
  226.                 bp->cnt = sizeof(struct phdr);            
  227.                 phdr = (struct phdr *)bp->data;
  228.                 phdr->type = TYPE_AX25;
  229.                 phdr->iface = hp->iface;
  230.                 bp->next = hp->rcvbuf;
  231.                 enqueue(&Hopper,bp);       /* queue it in */
  232.  
  233.                 /* packet queued - get buffer for next frame */
  234.                 hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  235.                 hp->rcp = hp->rcvbuf->data;
  236.                 hp->rcvbuf->cnt = 0;
  237.                 if(hp->rcvbuf == NULLBUF) {
  238.                     /* No memory, abort receiver */
  239.                     restore(i_state);
  240.                     printf("DISASTER! Out of Memory for Receive!\n");
  241.                     write_scc(CTL+base,R3,Rx8);
  242.                     return;
  243.                 }
  244.             } /* end good frame queued */
  245.         }  /* end check for active receive upon EOF */
  246.         hp->rstate = ACTIVE;    /* and clear error status */
  247.     } /* end EOF check */
  248.     restore(i_state);
  249. }
  250.  
  251. /* egchan transmit interrupt service routine
  252.  *
  253.  * The state variable tstate, along with some static pointers,
  254.  * represents the state of the transmit "process".
  255.  */
  256. static void
  257. egtxint(hp)
  258. register struct egchan *hp;
  259. {
  260.     register int16 base;
  261.     char i_state,c;
  262.  
  263.     i_state = dirps();
  264.  
  265.     if(hp->tstate != DEFER && hp->tstate)
  266.         hp->txints++;
  267.     base = hp->base;
  268.  
  269.     switch(hp->tstate) {
  270.     case FLAGOUT:
  271.         /* Here after CRC sent and Tx interrupt fires.
  272.          * To give the SCC a chance to get the FLAG
  273.          * out, we delay 100 Ms
  274.          */
  275.         hp->tstate = IDLE;    /* fall thru to IDLE */
  276.         waitmsec(10);        /* 100 msec wait for flag Tx */
  277.         /* Note, it may be possible to stuff out a
  278.          * meaningless character, wait for the interrupt
  279.          * then go to idle.  A delay is absolutely necessary
  280.          * here else the packet gets truncated prematurely
  281.          * when no other packet is waiting to be sent.
  282.          * IDLE state indicates either we are starting a brand new packet
  283.          * as a result of its being queued for transmission (egtxint called
  284.          * from eg_raw), or after a frame has been transmitted (as a
  285.          * result of a Tx buffer empty interrupt after the CRC/FLAG
  286.          */
  287.     case IDLE:
  288.         /* Transmitter idle. Find a frame for transmission */
  289.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF) {
  290.             /* Nothing to send - return to receive mode
  291.              * Tx OFF now - flag should have gone
  292.              */
  293.             rts(hp,OFF);
  294.             restore(i_state);
  295.             return;
  296.         }
  297.         /* If a buffer to send, we drop thru here */
  298.     case DEFER:        /* we may have deferred prev xmit attempt */
  299.         /* PPERSIST CALCULATION: we use the lower byte of the
  300.          * 8253 timer 0 count, as a random number (0-255).
  301.          * If the persist value is higher, wait one slot time
  302.          */
  303.         if(hp->params[PERSIST] >= peekb(0x40,0x6c))
  304.             waitmsec(hp->params[SLOTIME]);
  305.  
  306.         /* Check DCD so we don't step on a frame being received */
  307.         /* DCD is ACTIVE LOW on the SCC DCD pin, but the bit in R0 */
  308.         /* is SET when DCD is ACTIVE!! */
  309.  
  310.         if((read_scc(base+CTL,R0) & DCD) > 0) { /* Carrier Detected? */
  311.             hp->tstate = DEFER;    /* defer xmit */
  312.             /* don't release dequeued buffer...*/
  313.             restore(i_state);
  314.             return;
  315.         }
  316.  
  317.         rts(hp,ON);   /* Transmitter on */
  318.         /* ints not enabled yet */
  319.  
  320.         /* Get next char to send */
  321.         pullup(&hp->sndbuf,&c,1);        /* one char at a time */
  322.         write_scc(CTL+base,R0,RES_Tx_CRC);    /* reset for next frame */
  323.         outportb(base+DATA,c);        /* First char out now */
  324.  
  325.         /* select transmit interrupts to enable */
  326.  
  327.         write_scc(CTL+base,R15,TxUIE);        /* allow Underrun int only */
  328.         write_scc(CTL+base,R1,TxINT_ENAB|EXT_INT_ENAB);  /* Tx/Extern ints on */
  329.         write_scc(CTL+base,R9,MIE|NV);        /* master enable */
  330.         /* enable interrupt latch on board */
  331.         outportb(hp->dmactrl,INTENABLE);
  332.  
  333.         hp->tstate = ACTIVE;    /* char going out now */
  334.         restore(i_state);
  335.         return;
  336.  
  337.     case ACTIVE:
  338.         /* Here we are actively sending a frame */
  339.         if(pullup(&hp->sndbuf,&c,1) == 1) {
  340.             outportb(hp->base+DATA,c);    /* next char is gone */
  341.             /* stuffing a char satisfies Interrupt condition */
  342.         } else {
  343.             /* No more to send - just stop till underrun int */
  344.             hp->tstate = UNDERRUN;
  345.             free_p(hp->sndbuf);
  346.             /* now we reset the EOM latch & enable underrun int */
  347.             write_scc(CTL+base,R0,RES_EOM_L);    /* send CRC at underrun */
  348.             write_scc(CTL+hp->base,R0,RES_Tx_P); /* reset Tx Int Pend */
  349.         }
  350.         restore(i_state);
  351.         return;     /* back to wait for interrupt */
  352.  
  353.     case UNDERRUN:
  354.         /*
  355.          * This state is handled by an UNDERRUN interrupt, which
  356.          * is an External Status interrupt.  At UNDERRUN, the
  357.          * UNDERRUN/EOM latch in R0 will be 0, so the SCC will send
  358.          * CRC and ending flag.  After the CRC clears the Tx buffer,
  359.          * a TX BUFF EMPTY interrupt will fire.  At that time, we
  360.          * should be in FLAGOUT state, ready to send another frame
  361.          * if one is there to send.
  362.          */
  363.         break;
  364.     } /* end switch */
  365.     restore(i_state);
  366. }
  367.  
  368. /* SET Transmit or Receive Mode
  369.  * Set RTS (request-to-send) to modem on Transmit
  370.  */
  371. static void
  372. rts(hp,x)
  373. register struct egchan *hp;
  374. int16 x;
  375. {
  376. int16 tc;
  377. long br;
  378.  
  379.     /* Reprogram BRG and turn on transmitter to send flags */
  380.     if(x == ON) {                /* Turn Tx ON and Receive OFF */
  381.         write_scc(CTL+hp->base,R3,Rx8);    /* Rx off */
  382.         waitmsec(50);            /* 500 msec delay before on */
  383.         hp->rstate = IDLE;
  384.         write_scc(CTL+hp->base,R9,0);    /* Interrupts off */
  385.         br = hp->speed;         /* get desired speed */
  386.         tc = (XTAL/br)-2;        /* calc 1X BRG divisor */
  387.         write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  388.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  389.  
  390.         write_scc(CTL+hp->base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);
  391.         /* Transmitter now on */
  392.         write_scc(CTL+hp->base,R0,RES_Tx_CRC);/* CRC reset */
  393.         waitmsec(hp->params[TXDELAY]);      /* Delay after Tx on */
  394.     } else {    /* Tx OFF and Rx ON */
  395.         hp->tstate = IDLE;
  396.         write_scc(CTL+hp->base,R5,Tx8|DTR);     /* TX off now */
  397.         write_scc(CTL+hp->base,R0,ERR_RES);     /* reset error bits */
  398.  
  399.         write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  400.         write_scc(CTL+hp->base,R15,BRKIE);        /* allow ABORT int */
  401.  
  402.         /* delay for squelch tail before enable of Rx */
  403.         waitmsec(hp->params[SQUELDELAY]);    /* keep it up  */
  404.  
  405.         /* Reprogram BRG for 32x clock for receive DPLL */
  406.         write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  407.         br = hp->speed;             /* get desired speed */
  408.         tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  409.         write_scc(CTL+hp->base,R12,tc&0xFF);    /* lower byte */
  410.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF);    /* upper bite */
  411.         write_scc(CTL+hp->base,R14,BRSRC|SEARCH);    /* SEARCH mode, keep BRG source */
  412.         write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  413.  
  414.         /* Now, turn on the receiver and hunt for a flag */
  415.         write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  416.         hp->rstate = ACTIVE;            /* Normal state */
  417.     }
  418. }
  419.  
  420. /* Initialize eg controller parameters */
  421. static void
  422. egchanparam(hp)
  423. register struct egchan *hp;
  424. {
  425.     int16 tc;
  426.     long br;
  427.     char i_state;
  428.     register int16 base;
  429.  
  430.     /* Initialize 8530 channel for SDLC operation */
  431.  
  432.     base = hp->base;
  433. #ifdef    notdef
  434.     printf("Initializing Channel %c - Base = %x\n",base&2?'A':'B',base);
  435. #endif
  436.     i_state = dirps();
  437.  
  438.     switch(base & 2){
  439.     case 2:
  440.         write_scc(CTL+base,R9,CHRA);    /* Reset channel A */
  441.         break;
  442.     case 0:
  443.         write_scc(CTL+base,R9,CHRB);    /* Reset channel B */
  444.         break;
  445.     }
  446.  
  447.     /* Deselect all Rx and Tx interrupts */
  448.     write_scc(CTL+base,R1,0);
  449.  
  450.     /* Turn off external interrupts (like CTS/CD) */
  451.     write_scc(CTL+base,R15,0);
  452.  
  453.     /* X1 clock, SDLC mode */
  454.     write_scc(CTL+base,R4,SDLC|X1CLK);           /* SDLC mode and X1 clock */
  455.  
  456.     /* Now some misc Tx/Rx parameters */
  457.     /* CRC PRESET 1, NRZI Mode */
  458.     write_scc(CTL+base,R10,CRCPS|NRZI);
  459.  
  460.     /* Set up BRG and DPLL multiplexers */
  461.     /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
  462.     write_scc(CTL+base,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
  463.  
  464.     /* Null out SDLC start address */
  465.     write_scc(CTL+base,R6,0);
  466.  
  467.     /* SDLC flag */
  468.     write_scc(CTL+base,R7,FLAG);
  469.  
  470.     /* Set up the Transmitter but don't enable it */
  471.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  472.     write_scc(CTL+base,R5,Tx8|DTR);
  473.  
  474.     /* Receiver - intial setup only - more later */
  475.     write_scc(CTL+base,R3,Rx8);            /* 8 bits/char */
  476.  
  477.     /* Setting up BRG now - turn it off first */
  478.     write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  479.  
  480.     /* set the 32x time constant for the BRG in Receive mode */
  481.  
  482.     br = hp->speed;             /* get desired speed */
  483.     tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  484.  
  485.     write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  486.     write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  487.  
  488.     /* Time to set up clock control register for RECEIVE mode
  489.      * Eagle has xtal osc going to pclk at 3.6864 Mhz
  490.      * The BRG is sourced from that, and set to 32x clock
  491.      * The DPLL is sourced from the BRG, and feeds the TRxC pin
  492.      * Transmit clock & Receive clock come from DPLL
  493.      */
  494.  
  495.     /* Following subroutine sets up and ENABLES the receiver */
  496.     rts(hp,OFF);           /* TX OFF and RX ON */
  497.  
  498.     write_scc(CTL+hp->base,R14,BRSRC|SSBR);       /* DPLL from BRG, BRG source is PCLK */
  499.     write_scc(CTL+hp->base,R14,BRSRC|SEARCH);       /* SEARCH mode, keep BRG source */
  500.  
  501.     write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  502.  
  503.     /* enable the receive interrupts */
  504.  
  505.     write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  506.     write_scc(CTL+hp->base,R15,BRKIE);        /* ABORT int */
  507.     write_scc(CTL+hp->base,R9,MIE|NV);    /* master enable */
  508.  
  509.     /* enable interrupt latch on board */
  510.     outportb(hp->dmactrl,INTENABLE);
  511.  
  512.     /* Now, turn on the receiver and hunt for a flag */
  513.     write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  514.  
  515.     restore(i_state);
  516. }
  517.  
  518. /* Attach a EAGLE interface to the system
  519.  * argv[0]: hardware type, must be "eagle"
  520.  * argv[1]: I/O address, e.g., "0x300"
  521.  * argv[2]: vector, e.g., "2"
  522.  * argv[3]: mode, must be:
  523.  *        "ax25" (AX.25 UI frame format)
  524.  * argv[4]: interface label, e.g., "eg0"
  525.  * argv[5]: receiver packet buffer size in bytes
  526.  * argv[6]: maximum transmission unit, bytes
  527.  * argv[7]: interface speed, e.g, "1200"
  528.  */
  529. int
  530. eg_attach(argc,argv,p)
  531. int argc;
  532. char *argv[];
  533. void *p;
  534. {
  535.     register struct iface *if_pca,*if_pcb;
  536.     struct egchan *hp;
  537.     int dev;
  538.  
  539.     /* Quick check to make sure args are good and mycall is set */
  540.     if(strcmp(argv[3],"ax25") != 0){
  541.         printf("Mode %s unknown for interface %s\r\n",
  542.             argv[3],argv[4]);
  543.         return -1;
  544.     }
  545.     if(if_lookup(argv[4]) != NULLIF){
  546.         printf("Interface %s already exists\n",argv[4]);
  547.         return -1;
  548.     }
  549.     axarp();
  550.     if(Mycall.call[0] == '\0'){
  551.         printf("set mycall first\r\n");
  552.         return -1;
  553.     }
  554.     /* Note: More than one card can be supported if you give up a COM:
  555.      * port, thus freeing up an IRQ line and port address
  556.      */
  557.  
  558.     if(Egnbr >= EGMAX) {
  559.         printf("Only 1 EAGLE controller supported right now!\r\n");
  560.         return -1;
  561.     }
  562.     dev = Egnbr++;
  563.  
  564.     /* Initialize hardware-level control structure */
  565.     Eagle[dev].addr = htoi(argv[1]);
  566.     Eagle[dev].vec = htoi(argv[2]);
  567.  
  568.     /* Save original interrupt vector */
  569.     Eagle[dev].oldvec = getirq(Eagle[dev].vec);
  570.  
  571.     /* Set new interrupt vector */
  572.     if(setirq(Eagle[dev].vec,eghandle[dev]) == -1){
  573.         printf("IRQ %u out of range\n",Eagle[dev].vec);
  574.         Egnbr--;
  575.         return -1;
  576.     }
  577.     /* Create interface structures and fill in details */
  578.     if_pca = (struct iface *)calloc(1,sizeof(struct iface));
  579.     if_pcb = (struct iface *)calloc(1,sizeof(struct iface));
  580.  
  581.     /* Append "a" to interface associated with A channel */
  582.     if_pca->name = malloc((unsigned)strlen(argv[4])+2);
  583.     strcpy(if_pca->name,argv[4]);
  584.     strcat(if_pca->name,"a");
  585.     /* Append "b" to iface associated with B channel */
  586.     if_pcb->name = malloc((unsigned)strlen(argv[4])+2);
  587.     strcpy(if_pcb->name,argv[4]);
  588.     strcat(if_pcb->name,"b");
  589.  
  590.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  591.     if_pcb->ioctl = if_pca->ioctl = eg_ctl;
  592.     if_pca->dev = 2*dev;            /* eg0a */
  593.     if_pcb->dev = 2*dev + 1;        /* eg0b */
  594.     if_pcb->stop = if_pca->stop = eg_stop;
  595.     if_pcb->output = if_pca->output = ax_output;
  596.     if_pcb->raw = if_pca->raw = eg_raw;
  597.  
  598.     if(strcmp(argv[3],"ax25") == 0) {
  599.         /* Must be true, was checked at top */
  600.         if_pcb->send = if_pca->send = ax_send;
  601.         if(if_pcb->hwaddr == NULLCHAR)
  602.             if_pcb->hwaddr = malloc(sizeof(Mycall));
  603.         memcpy(if_pcb->hwaddr,(char *)&Mycall,sizeof(Mycall));
  604.         if(if_pca->hwaddr == NULLCHAR)
  605.             if_pca->hwaddr = malloc(sizeof(Mycall));
  606.         memcpy(if_pca->hwaddr,(char *)&Mycall,sizeof(Mycall));
  607.     }
  608.     /* Link em in to the interface chain */
  609.     if_pca->next = if_pcb;
  610.     if_pcb->next = Ifaces;
  611.     Ifaces = if_pca;
  612.  
  613.     /* set params in egchan table for CHANNEL B */
  614.  
  615.     hp = &Egchan[2*dev+1];                /* eg1 is offset 1 */
  616.     hp->iface = if_pcb;
  617.     hp->stata = Eagle[dev].addr + CHANA + CTL;    /* permanent status */
  618.     hp->statb = Eagle[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  619.     hp->dmactrl = Eagle[dev].addr + DMACTRL;    /* Eagle control reg */
  620.     hp->speed = (int16)atoi(argv[7]);
  621.     hp->base = Eagle[dev].addr + CHANB;
  622.     hp->bufsiz = atoi(argv[5]);
  623.     hp->tstate = IDLE;
  624.     /* default KISS Params */
  625.     hp->params[TXDELAY] = 25;        /* 250 Ms */
  626.     hp->params[PERSIST] = 64;        /* 25% persistence */
  627.     hp->params[SLOTIME] = 10;        /* 100 Ms */
  628.     hp->params[SQUELDELAY] = 20;        /* 200 Ms */
  629.  
  630.     write_scc(CTL+hp->stata,R9,FHWRES);     /* Hardware reset */
  631.                         /* one time only */
  632.     /* Disable interrupts with Master interrupt ctrl reg */
  633.     write_scc(CTL+hp->stata,R9,0);
  634.  
  635.     egchanparam(hp);
  636.  
  637.     /* Pre-allocate a receive buffer */
  638.     hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  639.     if(hp->rcvbuf == NULLBUF) {
  640.         /* No memory, abort receiver */
  641.         printf("EGATTACH: No memory available for Receive buffers\n");
  642.         /* Restore original interrupt vector */
  643.         setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  644.         Egnbr--;
  645.         return(-1);
  646.     }
  647.     hp->rcp = hp->rcvbuf->data;
  648.     hp->rcvbuf->cnt = 0;
  649.     hp->sndq = NULLBUF;
  650.  
  651.     /* set params in egchan table for CHANNEL A */
  652.     hp = &Egchan[2*dev];            /* eg0a is offset 0 */
  653.     hp->iface = if_pca;
  654.     hp->speed = (int16)atoi(argv[7]);
  655.     hp->base = Eagle[dev].addr + CHANA;
  656.     hp->bufsiz = atoi(argv[5]);
  657.     hp->tstate = IDLE;
  658.     /* default KISS Params */
  659.     hp->params[TXDELAY] = 25;        /* 250 Ms */
  660.     hp->params[PERSIST] = 64;        /* 25% persistence */
  661.     hp->params[SLOTIME] = 10;        /* 100 Ms */
  662.     hp->params[SQUELDELAY] = 20;        /* 200 Ms */
  663.  
  664.     egchanparam(hp);
  665.  
  666.     /* Pre-allocate a receive buffer */
  667.     hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  668.     if(hp->rcvbuf == NULLBUF) {
  669.         /* No memory, abort receiver */
  670.         printf("EGATTACH: No memory available for Receive buffers\n");
  671.         /* Restore original interrupt vector */
  672.         setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  673.         Egnbr--;
  674.         return -1;
  675.     }
  676.     hp->rcp = hp->rcvbuf->data;
  677.     hp->rcvbuf->cnt = 0;
  678.     hp->sndq = NULLBUF;
  679.  
  680.     write_scc(CTL+hp->base,R9,MIE|NV);        /* master interrupt enable */
  681.  
  682.     /* Enable interrupts on the EAGLE card itself */
  683.     outportb(hp->dmactrl,INTENABLE);
  684.  
  685.     /* Enable interrupt */
  686.     maskon(Eagle[dev].vec);
  687.  
  688.     return 0;
  689. }
  690.  
  691.  
  692. /* Shut down interface */
  693. static int
  694. eg_stop(iface)
  695. struct iface *iface;
  696. {
  697.     int16 dev;
  698.  
  699.     dev = iface->dev;
  700.     if(dev & 1)
  701.         return 0;
  702.     dev >>= 1;    /* Convert back into eagle number */
  703.  
  704.     /* Turn off interrupts */
  705.     maskoff(Eagle[dev].vec);
  706.  
  707.     /* Restore original interrupt vector */
  708.     setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  709.  
  710.     /* Force hardware reset */
  711.     write_scc(CTL+Eagle[dev].addr + CHANA,R9,FHWRES);
  712.  
  713.     /* resets interrupt enable on eagle card itself */
  714.     outportb(Eagle[dev].addr+DMACTRL,0);
  715.     return 0;
  716. }
  717.  
  718. /* Send raw packet on eagle card */
  719. static int
  720. eg_raw(iface,bp)
  721. struct iface *iface;
  722. struct mbuf *bp;
  723. {
  724.     char kickflag;
  725.     struct egchan *hp;
  726.  
  727.     dump(iface,IF_TRACE_OUT,TYPE_AX25,bp);
  728.     hp = &Egchan[iface->dev];
  729.     kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);    /* clever! flag=1 if something in queue */
  730.     enqueue(&hp->sndq,bp);
  731.     if(kickflag)            /* simulate interrupt to xmit */
  732.         egtxint(hp);        /* process interrupt */
  733.     return 0;
  734. }
  735. /* routine to delay n increments of 10 milliseconds
  736.  * about right on a turbo XT - will be slow on 4.77
  737.  * Still looking for a way to use the 8253 timer...
  738.  */
  739. static void
  740. waitmsec(n)
  741. int n;
  742. {
  743.     long i;
  744.  
  745.     for(i=0L; i < (200L*n); i++)
  746.         ;  /* simple loop delay */
  747. }
  748.  
  749. /* display EAGLE Channel stats */
  750. int
  751. doegstat(argc,argv,p)
  752. int argc;
  753. char *argv[];
  754. void *p;
  755. {
  756.     struct egchan *hp0, *hp1;
  757.     int i;
  758.  
  759.     for(i=0; i<EGMAX; i++) {
  760.         hp0 = &Egchan[i];
  761.         hp1 = &Egchan[i+1];
  762.  
  763.         printf("EAGLE Board Statistics:\n\n");
  764.         printf("Base Addr\tRxints\tTxints\tExints\tEnqued\tCrcerr\tAborts\tRxOvers\tRFrames\n");
  765.         printf("---------\t------\t------\t------\t------\t------\t------\t-------\t-------\n");
  766.         printf("0x%x\t\t%ld\t%ld\t%ld\t%d\t%d\t%d\t%d\t%d\nRcv State=%s\n", hp0->base, hp0->rxints,
  767.             hp0->txints, hp0->exints, hp0->enqueued, hp0->crcerr, hp0->aborts,
  768.             hp0->rovers,hp0->rxframes,
  769.             hp0->rstate==0?"IDLE":hp0->rstate==1?"ACTIVE":hp0->rstate==2?"RXERROR":hp0->rstate==3?"RXABORT":"TOOBIG");
  770.  
  771.         printf("0x%x\t\t%ld\t%ld\t%ld\t%d\t%d\t%d\t%d\t%d\nRcv State=%s\n\n", hp1->base, hp1->rxints,
  772.             hp1->txints, hp1->exints, hp1->enqueued, hp1->crcerr, hp1->aborts,
  773.             hp1->rovers,hp1->rxframes,
  774.             hp1->rstate==0?"IDLE":hp1->rstate==1?"ACTIVE":hp1->rstate==2?"RXERROR":hp1->rstate==3?"RXABORT":"TOOBIG");
  775.     }
  776.     return 0;
  777. }
  778.  
  779. /* Subroutine to set kiss params in channel tables */
  780. static int
  781. eg_ctl(iface,argc,argv)
  782. struct iface *iface;
  783. int argc;
  784. char *argv[];
  785. {
  786.     struct egchan *hp;
  787.     int p, v;
  788.  
  789.     if(argc < 2){
  790.         printf("Insufficient parameters\r\n");
  791.         return 1;
  792.     }
  793.     hp = &Egchan[iface->dev];        /* point to channel table */
  794.     p = atoi(argv[0]);          /* parameter in binary */
  795.     if(p > 3){
  796.         printf("parameter %d out of range\r\n",p);
  797.         return 1;
  798.     }
  799.     v = atoi(argv[1]);          /* value to be loaded */
  800.     hp->params[p] = v;          /* Stuff in Kiss array */
  801.     return 0;
  802. }
  803.